﻿using YanhuaMMO;

/**
 * 本类中的方法从protobuf中拷贝，只使用了int压缩算法
 * 
 * @author heyang
 *
 */

/// <summary>
/// 本类中的方法从protobuf中拷贝，只使用了int压缩算法
/// </summary>
public class ProtobufUtil {
    /// <summary>
    /// Encode and write a varint. {@code value} is treated as unsigned, so it
    /// won't be sign-extended if negative.
    /// </summary>
    /// <param name="buf"></param>
    /// <param name="value"></param>
    public static void WriteRawVarInt32(ByteBuffer buf, int value) {
        WriteRawVarUint32(buf, (uint)value);
    }

    public static void WriteRawVarUint32(ByteBuffer buf, uint value) {
        while (true) {
            if ((value & ~0x7F) == 0) {
                WriteRawByte(buf, value);
                return;
            }
            else {
                WriteRawByte(buf, (value & 0x7F) | 0x80);
                value >>= 7;
            }
        }
    }

    public static void WriteRawVarUint64(ByteBuffer buf, long value) {
        while (true) {
            if ((value & ~0x7F) == 0) {
                WriteRawByte(buf, value);
                return;
            }
            else {
                WriteRawByte(buf, (value & 0x7F) | 0x80);
                value = (long)((ulong)value >> 7);
            }
        }
    }

    /// <summary>
    /// Write a single byte, represented by an integer value.
    /// </summary>
    /// <param name="buf"></param>
    /// <param name="value"></param>
    private static void WriteRawByte(ByteBuffer buf, uint value) {
        WriteRawByte(buf, (byte)value);
    }

    /// <summary>
    /// Write a single byte
    /// </summary>
    /// <param name="buf"></param>
    /// <param name="value"></param>
    private static void WriteRawByte(ByteBuffer buf, byte value) {
        buf.WriteByte(value);
    }

    private static void WriteRawByte(ByteBuffer buf, long value) {
        WriteRawByte(buf, (byte)value);
    }

    /// <summary>
    /// Read a raw VarInt from the stream. If larger than 32 bits, discard the
    /// upper bits.
    /// </summary>
    /// <param name="buf"></param>
    /// <returns></returns>
    public static int ReadRawVarInt32(ByteBuffer buf) {

        return (int)ReadRawVarInt64SlowPath(buf);
    }

    public static uint ReadRawVarUint32(ByteBuffer buf) {

        return (uint)ReadRawVarInt64SlowPath(buf);
    }


    /// <summary>
    /// Variant of readRawVarInt64 for when uncomfortably close to the limit.
    /// Visible for testing
    /// </summary>
    /// <param name="buf"></param>
    /// <returns></returns>
    private static long ReadRawVarInt64SlowPath(ByteBuffer buf) {
        long result = 0;
        for (var shift = 0; shift < 64; shift += 7) {
            var b = ReadRawByte(buf);
            result |= (long)(b & 0x7F) << shift;
            if ((b & 0x80) == 0) {
                return result;
            }
        }
        return 0;
    }

    public static long ReadRawVarUint64(ByteBuffer buf){
		return ReadRawVarInt64SlowPath(buf);
    }

    /// <summary>
    /// Read one byte from the input.
    /// @throws InvalidProtocolBufferException
    ///             The end of the stream or the current limit was reached.
    /// </summary>
    /// <param name="buf"></param>
    /// <returns></returns>
    private static byte ReadRawByte(ByteBuffer buf) {
        return buf.ReadByte();
    }

}
